
//
// 130301 - AH - Created.
// 130501 - AH - Documented that set property methods should throw 
//               GimNoPropertyDefinedException if property is not defined.
// 130503 - AH - getItemsWithProperty(String, Object, String).
// 130504a- AH - Replaced Collection with List as type request methods returns.
// 130504b- AH - getItemWithProperty(String, Object, String).
// 130504c- AH - Documented that setting of property should define property
//               in a default way if not defined.
// 130505 - AH - Implemented missing createRelation methods that accepts Item.
// 130517 - AH - getRelations(Item, String).
//

package org.japril.gim;

import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.japril.servlet.httpannotations.HttpProtocol;
import org.japril.servlet.httpannotations.HttpRequest;
import org.japril.servlet.httpannotations.HttpRequestParam;

/**
 * <p>
 *   Interface for objects that manages a Generic Item Model (GIM) realization.
 * </p>
 * @author Arne Halvorsen (AH)
 */
@HttpProtocol("Items")
public interface Items 
{
  /**
   * <p>
   *   Creates item of default 
   *   {@link Item#getType() type}.
   * </p>
   * @return Created.
   * @throws IOException If fails.
   */
  Item create() throws IOException;
  
  /**
   * <p>
   *   Creates item.
   * </p>
   * @param type Name on type of item to create, can be {@code null}: default is
   *             'item'.
   * @return Created.
   * @throws IllegalArgumentException If {@code type!=null} or the empty string 
   *         but not accepted. 
   * @throws IOException If fails.
   */
  @HttpRequest(desc="Creates Item")
  Item create(
    @HttpRequestParam(name="type", mandatory=true) String type)
    throws IOException;
  
  /**
   * <p>
   *   Deletes item.
   * </p>
   * @param item {@link Item} to delete.
   * @return {@code true} if deleted, {@code false} if did not find.
   * @throws IOException If fails.
   */
  boolean delete(Item item) throws IOException;
  
  /**
   * <p>
   *   Deletes item.
   * </p>
   * @param id Id for item to delete.
   * @return {@code true} if deleted, {@code false} if did not find.
   * @throws IOException If fails.
   */
  boolean delete(int id) throws IOException;
  
  /**
   * <p>
   *   Tells if an item exists.
   * </p>
   * @param id Id that identifies item.
   * @return {@code true} if exists, {@code false} if does not exists.
   * @throws IllegalArgumentException If {@code id<0}.
   * @throws IOException If fails. 
   */
  boolean exists(int id) throws IOException;
  
  /**
   * <p>
   *   Gets item.
   * </p>
   * @param id Id that identifies 
   *           {@link Item} to get.
   * @return {@link Item} or {@code null} if not found.
   * @throws IllegalArgumentException If {@code id<0}. 
   * @throws IOException If fails.
   */
  @HttpRequest(desc="Gets an item")
  Item getItem(
    @HttpRequestParam(name="id", mandatory=true) int id) 
    throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s of given
   *   {@link Item#getType() type}.
   * </p>
   * @return {@link Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getItems() throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s of given
   *   {@link Item#getType() type}.
   * </p>
   * @param type Type to get items for, may be {@code null}: default is to get
   *             all items.
   * @return {@link Item}s.
   * @throws IOException If fails.
   */
  List<Item> getItems(String type) throws IOException;
  
  /**
   * <p>
   *   Gets item with given property.
   * </p>
   * @param name Property's name.
   * @param val  Property's value.
   * @param type Name on type of item to query, can be {@code null}: default is
   *             'item'. 
   * @return Item or {@code null} found.
   * @throws IOException If fails.
   */
  Item getItemWithProperty(String name, Object val, String type)
    throws IOException;
  
  /**
   * <p>
   *   Gets items with given property.
   * </p>
   * @param name Property's name.
   * @param val  Property's value.
   * @param type Name on type of item to query, can be {@code null}: default is
   *             'item'. 
   * @return Items found.
   * @throws IOException If fails.
   */
  List<Item> getItemsWithProperty(String name, Object val, String type)
    throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'left and right roles' are 
   *   default.
   * </p>
   * @param li 'left' 
   *           {@link Item} of relationship.
   * @param ri 'right' 
   *           {@link Item} of relationship.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IOException If fails.
   */
  void createRelation(Item li, Item ri) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'left and right roles' are 
   *   default.
   * </p>
   * @param lid Id of 'left' item of relationship.
   * @param rid Id of 'right' item of relationship.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IOException If fails.
   */
  void createRelation(int lid, int rid) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'left role' is default.
   * </p>
   * @param li    'left' 
   *              {@link Item} of relationship.
   * @param ri    'right' 
   *              {@link Item} of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty 
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  void createRelation(Item li, Item ri, String rrole) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'left role' is default.
   * </p>
   * @param lid   Id of 'left' item of relationship.
   * @param rid   Id of 'right' item of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty 
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  void createRelation(int lid, int rid, String rrole) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'right role' is default.
   * </p>
   * @param li    'left' 
   *              {@link Item} of relationship.
   * @param lrole Role name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param ri    'right' 
   *              {@link Item} of relationship.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty 
   *         string but not accepted.
   * @throws IOException If fails.
   */
  void createRelation(Item li, String lrole, Item ri) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items where 'right role' is default.
   * </p>
   * @param lid   Id of 'left' item of relationship.
   * @param lrole Role name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param rid   Id of 'right' item of relationship.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty 
   *         string but not accepted.
   * @throws IOException If fails.
   */
  void createRelation(int lid, String lrole, int rid) throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items.
   * </p>
   * @param li    'left' 
   *              {@link Item} of relationship.
   * @param lrole Role name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param ri    'right' 
   *              {@link Item} of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty
   *         string but not accepted.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  void createRelation(Item li, String lrole, Item ri, String rrole)
    throws IOException;
  
  /**
   * <p>
   *   Creates relationship between items.
   * </p>
   * @param lid   Id of 'left' item of relationship.
   * @param lrole Role name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param rid   Id of 'right' item of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty
   *         string but not accepted.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  void createRelation(int lid, String lrole, int rid, String rrole)
    throws IOException;
  
  /**
   * <p>
   *   Delete relationship between items where 'left and right types' are 
   *   default.
   * </p>
   * @param l 'Left' item of relationship.
   * @param r 'Right' item of relationship.
   * @return {@code true} if was deleted, {@code false} if not found.
   * @throws IllegalArgumentException If one of the items does not exists.
   * @throws IOException If fails.
   */
  boolean deleteRelation(Item l, Item r) throws IOException;
  
  /**
   * <p>
   *   Delete relationship between items where 'left and right types' are 
   *   default.
   * </p>
   * @param lid Id of 'left' item of relationship.
   * @param rid Id of 'right' item of relationship.
   * @return {@code true} if was deleted, {@code false} if not found.
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IOException If fails.
   */
  boolean deleteRelation(int lid, int rid) throws IOException;
  
  /**
   * <p>
   *   Deletes relationship between items where 'left role' is default.
   * </p>
   * @param l     'Left' item of relationship.
   * @param r     'Right' item of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default type is 'right'.
   * @return {@code true} if was deleted, {@code false} if not found.              
   * @throws IllegalArgumentException If one of the items does not exists.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty 
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  boolean deleteRelation(Item l, Item r, String rrole) throws IOException;
  
  /**
   * <p>
   *   Deletes relationship between items where 'left role' is default.
   * </p>
   * @param lid   Id of 'left' item of relationship.
   * @param rid   Id of 'right' item of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @return {@code true} if was deleted, {@code false} if not found.              
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty 
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  boolean deleteRelation(int lid, int rid, String rrole) throws IOException;
  
  /**
   * <p>
   *   Deletes relationship between items where 'right role' is default.
   * </p>
   * @param lid   'Left' item of relationship.
   * @param lrole Type name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param rid   'Right' item of relationship.
   * @return {@code true} if was deleted, {@code false} if not found. 
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty 
   *         string but not accepted.
   * @throws IOException If fails.
   */
  boolean deleteRelation(Item l, String lrole, Item r) throws IOException;
  
  /**
   * <p>
   *   Deletes relationship between items where 'right role' is default.
   * </p>
   * @param lid   Id of 'left' item of relationship.
   * @param lrole Type name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param rid   Id of 'right' item of relationship.
   * @return {@code true} if was deleted, {@code false} if not found. 
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty 
   *         string but not accepted.
   * @throws IOException If fails.
   */
  boolean deleteRelation(int lid, String lrole, int rid) throws IOException;
  
  /**
   * <p>
   *   Delete relationship.
   * </p>
   * @param l     'Left' item of relationship. 
   * @param lrole Type name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param r     'Right' item of relationship.
   * @param rrole Type name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @return {@code true} if was deleted, {@code false} if not found.              
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty
   *         string but not accepted.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  boolean deleteRelation(Item l, String lrole, Item r, String rrole)
    throws IOException;
  
  /**
   * <p>
   *   Delete relationship.
   * </p>
   * @param lid   Id of 'left' item of relationship. 
   * @param lrole Role name of left item in relationship, may be {@code null} 
   *              or the empty string: default role is 'left'.
   * @param rid   Id of 'right' item of relationship.
   * @param rrole Role name of right item in relationship, may be {@code null}
   *              or the empty string: default role is 'right'.
   * @return {@code true} if was deleted, {@code false} if not found.              
   * @throws IllegalArgumentException If {@code lid<0 || rid<0} or one of the
   *         items does not exists.
   * @throws IllegalArgumentException If {@code lrole!=null} or the empty
   *         string but not accepted.
   * @throws IllegalArgumentException If {@code rrole!=null} or the empty
   *         string but not accepted.  
   * @throws IOException If fails.
   */
  boolean deleteRelation(int lid, String lrole, int rid, String rrole)
    throws IOException;
  
  /**
   * <p>
   *   Gets all relationships.
   * </p>
   * <p>
   *   This probably mostly useful as a debug tool with databases of few
   *   entities.
   * </p>
   * @return {@link ItemItem} objects representing relationships.
   * @throws IOException If fails.
   */
  List<ItemItem> getRelations() throws IOException;
  
  /**
   * <p>
   *   Gets all relationships that there is between a given 'left' item to
   *   'right' items of a given type.
   * </p>
   * @param lid   'Left' item.
   * @param rtype Type of 'right' items. May be {@code null} or the empty 
   *              string, default is 'item'.
   * @return {@link ItemItem} objects representing relationships.
   * @throws IOException If fails.
   */
  List<ItemItem> getRelations(Item li, String rtype) throws IOException;
  
  /**
   * <p>
   *   Gets all relationships that there is between a given 'left' item to
   *   'right' items of a given type.
   * </p>
   * @param lid   Id of 'left' item.
   * @param rtype Type of 'right' items. May be {@code null} or the empty 
   *              string, default is 'item'.
   * @return {@link ItemItem} objects representing relationships.
   * @throws IOException If fails.
   */
  List<ItemItem> getRelations(int lid, String rtype) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as left item in a relationship.
   * </p>
   * @param l {@code Item} at left.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getRightItem(Item l) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as left item in a relationship.
   * </p>
   * @param lid Id that identifies left item.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getRightItem(int lid) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as left item in a relationship.
   * </p>
   * @param l     {@code Item} at left.
   * @param rrole Type right items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getRightItem(Item l, String rrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as left item in a relationship.
   * </p>
   * @param lid   Id that identifies left item.
   * @param rrole Type right items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getRightItem(int lid, String rrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as left item in a relationship.
   * </p>
   * @param l {@code Item} at left.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  Collection<Item> getRightItems(Item l) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as left item in a relationship.
   * </p>
   * @param lid Id that identifies left item.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getRightItems(int lid) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as left item in a relationship.
   * </p>
   * @param l     {@code Item} at left.
   * @param rrole Type right items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getRightItems(Item l, String rrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as left item in a relationship.
   * </p>
   * @param lid   Id that identifies left item.
   * @param rrole Type right items has in relationship, may be {@code null}:
   *              default is to get of all types.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getRightItems(int lid, String rrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as right item in a relationship.
   * </p>
   * @param r {@code Item} at right.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getLeftItem(Item r) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as right item in a relationship.
   * </p>
   * @param rid Id that identifies right item.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getLeftItem(int rid) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as right item in a relationship.
   * </p>
   * @param r     {@code Item} at right.
   * @param lrole Role left items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getLeftItem(Item r, String lrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item} that has given item as right item in a relationship.
   * </p>
   * @param rid   Id that identifies right item.
   * @param lrole Role left items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@link Item} or {@code null} if none found.
   * @throws IOException If fails.
   */
  Item getLeftItem(int rid, String lrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as right item in a relationship.
   * </p>
   * @param r {@code Item} at right.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getLeftItems(Item r) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as right item in a relationship.
   * </p>
   * @param rid Id that identifies right item.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getLeftItems(int rid) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as right item in a relationship.
   * </p>
   * @param r     {@code Item} at right.
   * @param lrole Role left items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getLeftItems(Item r, String lrole) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@link Item}s that has given item as right item in a relationship.
   * </p>
   * @param rid   Id that identifies right item.
   * @param lrole Role left items has in relationship, may be {@code null}:
   *              default is to get of all roles.
   * @return {@code Item}s.
   * @throws IOException If fails. 
   */
  List<Item> getLeftItems(int rid, String lrole) throws IOException;
  
  //
  
  /**
   * <p>
   *   Defines a property for an 
   *   {@link Item}.
   * </p>
   * @param name       Property name.
   * @param nativeType Type specification for persistent storage system (i.e.
   *                   SQL type). 
   * @param flen       Length of database field (i.e. length of a VARCHAR
   *                   field). Can be {@code null} if not apply or use default
   *                   value of {@code 256}.
   * @param itemType   Type of item property is defined for, can be 
   *                   {@code null}: default is 'item'.
   * @return {@code true} if defined, {@code false} if already defined (this
   *         call had no effect).
   * @throws IOException If fails.         
   */
  boolean defineProperty(String name, String nativeType, Integer flen,
    String itemType) throws IOException; 
  
  /**
   * <p>
   *   Sets an 
   *   {@link Item}'s property.
   * </p>
   * <p>
   *   If property has not been 
   *   {@link #defineProperty(String, String, Integer, String) defined} this
   *   should define it in a default way.
   * </p>
   * @param item  {@link Item} to set property value for. 
   * @param name  Name on property.
   * @param value Property value, {@code null} if to delete.
   * @throws IOException If fails.
   */
  void setProperty(Item item, String name, Object value) throws IOException;
  
  /**
   * <p>
   *   Sets an 
   *   {@link Item}'s property.
   * </p>
   * @param id    Id that identifies item to set property value for. 
   * @param name  Name on property.
   * @param value Property value, {@code null} if to delete.
   * @throws IOException If fails.
   * @throws GimNoPropertyDefinedException If property not defined.
   */
  void setProperty(int id, String name, Object value) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@code String} property value.
   * </p>
   * @param id   {@link Item} to get property value for.
   * @param name Name on property.
   * @return Property value or {@code null} if not found.
   * @throws IOException If fails.
   * @throws GimNoPropertyDefinedException If property not defined. 
   */
  String getStringProperty(Item item, String name) throws IOException;
  
  /**
   * <p>
   *   Gets 
   *   {@code String} property value.
   * </p>
   * @param id   Id that identifies item to get property value for.
   * @param name Name on property.
   * @return Property value or {@code null} if not found.
   * @throws IOException If fails.
   */
  String getStringProperty(int id, String name) throws IOException;
  
  /**
   * <p>
   *   Gets {@code int} property value.
   * </p>
   * @param item {@link Item} that identifies item to get property value for.
   * @param name Name on property.
   * @return Property value or {@code null} if not found.
   * @throws IOException If fails.
   */
  Integer getIntProperty(Item item, String name) throws IOException;
  
  /**
   * <p>
   *   Gets {@code int} property value.
   * </p>
   * @param id   Id that identifies item to get property value for.
   * @param name Name on property.
   * @return Property value or {@code null} if not found.
   * @throws IOException If fails.
   */
  Integer getIntProperty(int id, String name) throws IOException;
  
}
